
#include <windows.h>
#include <scrnsave.h>
#include <commctrl.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#include <GL/gl.h>
#include <GL/glu.h>

#include "wgl.h"

#include "globals.h"

#include "about.h"
#include "viewing.h"
#include "general.h"
#include "rendering.h"
#include "coloring.h"

#include "resource.h"
#include "consts.h"
#include "removecontexthelpproc.h"

#include "tetrahedron.h"
#include "octahedron.h"
#include "cube.h"
#include "icosahedron.h"
#include "dodecahedron.h"

#include "schlicker.h"

Polyhedra* p = NULL;

int angle = 0, numcycles = 0;

bool displayable = false;
bool randommode = false;

void MakePolyhedra()
{
	if (p != NULL)
		delete p;

	if (cpolygon == 5)
	{
		randommode = true;

		// Random Polyhedra
		srand ( (unsigned int)time(NULL) +rand() );
		int random = rand() % 5;
		cpolygon = random;

		float alter = (float)(rand())/(RAND_MAX);
		cur_r = SchlickerKunnen(cpolygon)+alter;
		cur_i = 5 - cpolygon;
	}

	switch (cpolygon)
	{
	case 0:
		p = new Tetrahedron (1.0f, cur_i, cur_r);
		break;
	case 1:
		p = new Octahedron (1.0f, cur_i, cur_r);
		break;
	case 2:
		p = new Cube (1.0f, cur_i, cur_r);
		break;
	case 3:
		p = new Icosahedron (1.0f, cur_i, cur_r);
		break;
	case 4:
		p = new Dodecahedron (1.0f, cur_i, cur_r);
		break;
	}
	p -> SetModes (coloring_mode, colortheme);
	p -> SetColor (rcolor, gcolor, bcolor);
	p -> SetIterative ( iterative );
	p -> Make();

	displayable = true;
}

	/* Get the messages out of the message queue and ask the 
	   default screensaver procedure to handle them. */
DWORD WINAPI CheckMessages (LPVOID lpParameter)
{
	HWND hWnd = (HWND)lpParameter;		// hwindow
	MSG message;						// MSG for GetMessage

	while (!displayable)
	{
			// Get the message out of the message queue
		GetMessage (&message, hWnd, 0, 255);
			// Send the message to the default screen saver procedure
		DefScreenSaverProc (hWnd, message.message, message.lParam,
			message.wParam);
	}
	return 1;
}

	/* Create the thread that handles the messages and sends it
	   to default screen saver procedure */
void CreateThreadTube (HWND hWnd)
{
	HANDLE tHandle;
	DWORD IDThread;

		// Call the create-thread function
	tHandle = CreateThread (NULL, 0, CheckMessages, 
		(LPVOID)hWnd, 0, &IDThread);
}

void init (void)
{
	float light0_position[4] = {x_viewpos, y_viewpos, -z_viewpos,
		1.0};

	if (polygonmode == 2)
	{
		light0_position[2] -= 5;
	}

	glClearColor (0.0, 0.0, 0.0, 0.0);
	
	glLightfv (GL_LIGHT0, GL_POSITION, light0_position);	
	glEnable (GL_LIGHTING);
	glEnable (GL_LIGHT0);
	glEnable (GL_DEPTH_TEST);
	glEnable (GL_COLOR_MATERIAL);

	if (polygonmode == 0)
	{
		if (pointsmooth)
			glEnable (GL_POINT_SMOOTH);
		glPointSize ((float)pointsize);
		glPolygonMode (GL_FRONT_AND_BACK, GL_POINT);
	}
	else if (polygonmode == 1)
		glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
	else
		glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);

	MakePolyhedra();
}

void display (void)
{
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glPushMatrix();
		glRotatef ((float)angle, x_rotdir, y_rotdir, z_rotdir);
		p -> Draw();
	glPopMatrix();
}

void reshape (int w, int h)
{
	glViewport (0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity();
	gluPerspective (40.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0);
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt (x_viewpos, y_viewpos, z_viewpos, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}

void idle (void)
{
	angle = (angle + INC_VALUE) % 360;
	// If we have complete a full revolution and we are in change mode, change the list
	if (angle == 0)
	{
		numcycles++;
		if (numcycles==cycles && randommode && change)
		{
			numcycles = 0;
			cpolygon = 5;
			MakePolyhedra();
		}
	}
}

// Screen Saver Routines

// Screen Saver display window
LONG WINAPI ScreenSaverProc (HWND hWnd, UINT message, WPARAM wParam,
	 LPARAM lParam)
{
	static HDC hDC;
	static HGLRC hRC;

	static UINT uTimer;
	RECT rect;

	switch (message)
	{
	case WM_CREATE:
		uTimer = SetTimer (hWnd, 0, 0, NULL);
		EnableOpenGL (hWnd, &hDC, &hRC);
		LoadSettings();
		CreateThreadTube (hWnd);
		init();
		break;

	case WM_SIZE:
		GetClientRect (hWnd, &rect);
		reshape (rect.right, rect.bottom);
		InvalidateRect (hWnd, NULL, FALSE);
		break;

	case WM_TIMER:
		idle();
		display();
		SwapBuffers (hDC);
		break;

	case WM_DESTROY:
		if (uTimer)
			KillTimer (hWnd, uTimer);
		DisableOpenGL (hWnd, hDC, hRC);
		break;
	default:
		break;
	}

	return DefScreenSaverProc (hWnd, message, wParam, lParam);
}

// Screen Saver Configuration Dialog Box
BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, 
	 UINT message, WPARAM wParam, LPARAM lParam)
{
	PROPSHEETPAGE psp[5];
	PROPSHEETHEADER psh;
	INITCOMMONCONTROLSEX InitCtrls;		// For Registering Win32 CCs

	switch (message)
	{
	case WM_INITDIALOG:		// Handle only the initalization message
			// Fill up the struct to load the Windows95 common controls
			// Specify the size of the structure
		InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
			// Specify the type of classes to be loaded
		InitCtrls.dwICC = ICC_BAR_CLASSES | ICC_TAB_CLASSES;
			// Call the windows API to register the new controls
		InitCommonControlsEx (&InitCtrls);

		LoadSettings();

		memset (&psp[0], 0, sizeof(psp[0]));
		// Create the property sheet for the general settings
		psp[0].dwSize = sizeof (PROPSHEETPAGE);
		psp[0].dwFlags = PSP_USETITLE;
		psp[0].hInstance = hMainInstance;
		psp[0].pszTemplate = MAKEINTRESOURCE (IDD_SETTINGS_GENERAL);
		psp[0].pszIcon = NULL;
		psp[0].pfnDlgProc = ConfigureSettingsGeneral;
		psp[0].pszTitle = "General";
		psp[0].lParam = 0;

		memset (&psp[1], 0, sizeof(psp[1]));
		// Create the property page for the viewing settings
		psp[1].dwSize = sizeof (PROPSHEETPAGE);
		psp[1].dwFlags = PSP_USETITLE;
		psp[1].hInstance = hMainInstance;
		psp[1].pszTemplate = MAKEINTRESOURCE (IDD_SETTINGS_VIEWING);
		psp[1].pszIcon = NULL;
		psp[1].pfnDlgProc = ViewingConfigureDialog;
		psp[1].pszTitle = "Viewing";
		psp[1].lParam = 0;

		memset (&psp[2], 0, sizeof(psp[2]));
		// Create the property page for the rendering settings
		psp[2].dwSize = sizeof (PROPSHEETPAGE);
		psp[2].dwFlags = PSP_USETITLE;
		psp[2].hInstance = hMainInstance;
		psp[2].pszTemplate = MAKEINTRESOURCE (IDD_SETTINGS_RENDERING);
		psp[2].pszIcon = NULL;
		psp[2].pfnDlgProc = RenderingConfigureDialog;
		psp[2].pszTitle = "Rendering";
		psp[2].lParam = 0;

		memset (&psp[3], 0, sizeof(psp[3]));
		// Create the property page for the coloring settings
		psp[3].dwSize = sizeof (PROPSHEETPAGE);
		psp[3].dwFlags = PSP_USETITLE;
		psp[3].hInstance = hMainInstance;
		psp[3].pszTemplate = MAKEINTRESOURCE (IDD_SETTINGS_COLORING);
		psp[3].pszIcon = NULL;
		psp[3].pfnDlgProc = ColoringConfigureDialog;
		psp[3].pszTitle = "Coloring";
		psp[3].lParam = 0;

		memset (&psp[4], 0, sizeof(psp[4]));
		// Create the property page for the about settings
		psp[4].dwSize = sizeof (PROPSHEETPAGE);
		psp[4].dwFlags = PSP_USETITLE;
		psp[4].hInstance = hMainInstance;
		psp[4].pszTemplate = MAKEINTRESOURCE (IDD_SETTINGS_ABOUT);
		psp[4].pszIcon = NULL;
		psp[4].pfnDlgProc = AboutConfigureDialog;
		psp[4].pszTitle = "About";
		psp[4].lParam = 0;

		memset (&psh, 0, sizeof(psh));
		// Create the property sheet dialog
		psh.dwSize = sizeof (PROPSHEETHEADER);
		psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW |
			PSH_USECALLBACK;
		psh.hwndParent = hDlg;
		psh.hInstance = hMainInstance;
		psh.pszIcon = NULL;
		psh.pszCaption = (LPSTR)SETTINGS_TITLE;
		psh.nPages = sizeof (psp) / sizeof (PROPSHEETPAGE);
		psh.nStartPage = 0;
		psh.ppsp = (PROPSHEETPAGE*) &psp;
		psh.pfnCallback = RemoveContextHelpProc;

		PropertySheet (&psh);

		// Kill the default dialog before it can show it's ugly face
		EndDialog (hDlg, LOWORD(wParam) == ID_OK);

		return TRUE;
		break;
	}

	return FALSE;
}

BOOL WINAPI RegisterDialogClasses (HANDLE hInst)
{
	return TRUE;
}